import VueRouter from 'vue-router'
import UrlUtil from '../utils/url'
import ArrayUtil from '../utils/array'
import clone from 'clone'

const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push (location, onResolve, onReject) {
  if (onResolve || onReject) return originalPush.call(this, location, onResolve, onReject)
  return originalPush.call(this, location).catch(err => err)
}

const staticRouteList = [],
  _views = {},
  rootList = [],
  routeConfig = {
    pc: {
      routeList: [],
      routeMap: {},
      dynamic: {}
    },
    mobile: {
      routeList: [],
      routeMap: {},
      dynamic: {}
    }
  }

let appName = null

const options = {
  /**
   * 添加多个根路由（需要登录权限）
   * @param {*} routes
   */
  setRoots (roots) {
    const map = {}
    rootList.map(root => {
      map[root.path] = root
    })
    roots.map(root => {
      root.path = `/${root.path.split('/').filter(str => str !== '').join('/')}`
      if (map[root.path]) {
        console.warn(`[router] 路由被覆盖: ${root.path}`)
        rootList.splice(rootList.indexOf(map[root.path]), 1, root)
      } else {
        rootList.push(root)
      }

      // 根路由添加默认路由
      this.registRootChildren([], root)
    })
  },
  getRoots () {
    return rootList
  },
  /**
   * 添加静态路由
   */
  registStaticRoutes (routes) {
    routes.map(r => {
      this.addRoute(r)
      staticRouteList.push(r)
    })
  },
  /**
   * 路由跳转
   */
  onBeforeEach (to, form, next) {

  },
  /**
   * 路由跳转完成
   */
  onAfterEach () {

  },
  /**
   * 动态路由构建完成调用此方法
   */
  afterDynamicRoutesBuild (roots) {
    return new Promise((resolve) => {
      resolve(roots)
    })
  },
  /**
   * 在根路由下注册静态子路由
   */
  registRootChildren (children, root) {
    if (typeof (root) == 'string') {
      root = rootList.find(route => route.path == root)
    }
    !root && (root = rootList.find(route => route.path == '/'))
    !root && console.error('未设置默认根路由')

    root.children = root.children || []
    children = root.children.filter(item => !item.meta?._parent).concat(children)
    root.children = []

    children = ArrayUtil.flat(children, 'children', 0).filter(item => {
      item.meta = item.meta || {}
      item.title = item.meta.title
      if (item._parent) {
        item.meta._parent = item._parent
        item.meta._parent.authorize = item.meta._parent.authorize || []
        item.meta.code && item.meta._parent.authorize.push(item.meta.code)
      }

      if (!item.path) {
        const index = item.meta._parent.children.indexOf(item)
        item.meta._parent.splice(index, 1)
        return false
      }

      // path为绝对路径，则提升该节点到父节点同一级（从父节点的 children 中移除该节点）
      if (item.path.startsWith('/') && !item.initialized) {
        // 标记为绝对路径
        item.meta.absolute = true
      }

      if (item.path.startsWith('http://') || item.path.startsWith('https://')) {
        item.meta.absolute = true
      } else if (!item.path.startsWith('/')) {
        // 补全相对路径
        const pathList = ArrayUtil.getParents(item).filter(p => p.path && !p.path.startsWith('https://') && !p.path.startsWith('http://')).map(p => p.path)
        item.path = `/${pathList.join('/')}/${item.path}`.replace(/\/\/+/g, '/')
      }

      item.initialized = true
      return item
    })
    root.children = children.filter(item => !item.meta._parent || item.meta.absolute)
  },
  /**
   * 设置根路由重定向
   */
  setRootRedirect (redirectURL) {
    const root = rootList.find(route => route.path == '/' || route.path == '')
    root.redirect = redirectURL
  },
  /**
   * 注册动态路由
   * @param {*} routesList
   * @param {*} root
   */
  registDynamicRoutes (routesList, key = 'pc') {
    const { dynamic } = routeConfig[key]
    routesList.map(route => {
      route.meta = route.meta || {}
      route.meta.hidden = true
      dynamic[route.path] = route
    })
  },
  /**
   * 添加页面视图组件
   */
  registViews (views) {
    Object.assign(_views, views)
  },
  /**
   * 重定向登录
   */
  redirectLogin: null,
  /**
   * 需要登录信息, 返回Promise对象
   */
  onNeedLoginInfo: null,
  /**
   * 获取页面视图组件
   */
  getViews () {
    return _views
  },
  getView (name) {
    return _views[name] || null
  },
  setDocumentTitle (to) {
    !appName && (appName = this.store.getAppConfig('_appName', ''))
    const routeList = to.matched.concat()
    let meta = routeList.length == 0 ? {} : routeList.pop().meta
    while (meta.hidden) {
      meta = routeList.pop().meta
    }
    if (meta?.title) {
      document.title = meta.title + ' - ' + appName
    } else {
      document.title = appName || ''
    }
  },
  /**
   * 加载路由配置文件
   * @param {*} fileList
   * @param {*} key
   */
  loadRouteConfigFiles (fileList, key = 'pc') {
    const { routeList, routeMap } = routeConfig[key]
    fileList.keys().map(key => {
      // 树结构路由配置扁平化处理
      const level = routeList.filter(route => !route.meta._parent).length

      ArrayUtil.flat(fileList(key).default, 'children', level).map(item => {
        item.meta = item.meta || {}
        item.title = item.meta.title
        item.meta._parent = item._parent

        if (!item.path) {
          return
        }

        // path为绝对路径，则提升该节点到父节点同一级（从父节点的 children 中移除该节点）
        if (item.path.startsWith('/')) {
          // item._parent?.children?.splice(item._parent?.children.indexOf(item), 1)
          // 标记为绝对路径
          item.meta.absolute = true
        }

        if (item.path.startsWith('http://') || item.path.startsWith('https://')) {
          item.meta.absolute = true
        } else if (!item.path.startsWith('/')) {
          // 补全相对路径
          const pathList = ArrayUtil.getParents(item).filter(p => p.path && !p.path.startsWith('https://') && !p.path.startsWith('http://')).map(p => p.path)
          item.path = `/${pathList.join('/')}/${item.path}`.replace(/\/\/+/g, '/')
        }

        if (routeMap[item.path]) {
          console.warn(`[router] 路由被覆盖: ${item.path}`)
          routeList.splice(routeList.findIndex(r => r.path == item.path), 1)
        }
        routeList.push(item)
        routeMap[item.path] = item
      })
    })
  },

  getRouteConfig (key) {
    return clone(routeConfig[key])
  },

  /**
   * 前置路由守卫
   */
  beforeEachFn (to, from, next) {
    this.setDocumentTitle(to)
    if (to.meta.static) {
      to.meta.from = from.meta.id || from.path
    }
    // to.query && (to.query.timestamp = new Date().getTime())
    this.onBeforeEach(to, from, next)
    if (getNotNeedLoginPath().includes(to.path)) {
      next()
    } else if (!this.store.getLoginUser()) {
      this.onNeedLoginInfo().then(() => {
        // 用户信息初始化后，跳转下一个路由
        if (this.store.getLoginUser()) {
          nextRoute(to, from, next)
        } else {
          console.error('未获取到登录用户信息')
        }
      }).catch(e => {
        const redirect = UrlUtil.getURLParam('redirect')
        this.redirectLogin(redirect)
      })
    } else {
      next()
    }
  }
}

function getNotNeedLoginPath () {
  return staticRouteList.map(r => {
    return r.path
  })
}

function nextRoute (to, from, next) {
  // 请求带有 redirect 重定向时，登录自动重定向到该地址
  const redirect = decodeURIComponent(from.query.redirect || to.path)
  if (to.path === redirect) {
    next({ ...to, replace: true })
  } else {
    // 跳转到目标路由
    next({ path: redirect })
  }
}

export function Router (Vue, store) {
  Vue.use(VueRouter)
  const router = new VueRouter({
    base: process.env.BASE_URL || '/',
    mode: process.env.BASE_URL.startsWith('/') ? 'history' : 'hash',
    routes: [],
    scrollBehavior (to, from, savedPosition) {
      if (to.meta.keepAlive) {
        return savedPosition || to.meta.scroll || { x: 0, y: 0 }
      }
      return { x: 0, y: 0 }
    }
  })
  router.isHash = router.mode == 'hash'

  router.store = store

  Object.assign(router, options)

  router.beforeEach((to, from, next) => {
    router.beforeEachFn(to, from, next)
  })

  router.afterEach((to, from, next) => {
    router.onAfterEach(to, from, next)
  })
  return router
}